home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / modem.c < prev    next >
C/C++ Source or Header  |  1998-04-25  |  58KB  |  2,567 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/modem.c,v $
  15.  * $Revision: 1.6 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/04/25 08:40:01 $
  18.  * 
  19.  * Modem support code
  20.  *
  21.  * $Log: modem.c,v $
  22.  * Revision 1.6  1998/04/25 08:40:01  nobody
  23.  * Transport layer now selectable
  24.  *
  25.  * Revision 1.5  1998/04/24 14:29:30  tfrieden
  26.  * Multiplayer now really works
  27.  *
  28.  * Revision 1.4  1998/04/14 23:55:42  tfrieden
  29.  * socket stuff added
  30.  *
  31.  * Revision 1.3  1998/04/13 01:18:29  tfrieden
  32.  * *** empty log message ***
  33.  *
  34.  * Revision 1.2  1998/04/11 22:14:55  hfrieden
  35.  * First try of an Amiga serial mode
  36.  *
  37.  * Revision 1.1.1.1  1998/03/03 15:12:24  nobody
  38.  * reimport after crash from backup
  39.  *
  40.  * Revision 1.1.1.1  1998/02/13  20:20:49  hfrieden
  41.  * Initial Import
  42.  */
  43.  
  44. #define DOS4G
  45.  
  46. #pragma off (unreferenced)
  47. static char rcsid[] = "$Id: modem.c,v 1.6 1998/04/25 08:40:01 nobody Exp $";
  48. #pragma on (unreferenced)
  49.  
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <time.h>
  54.  
  55. //#include "fast.h" // Commlib stuff //Don't have fast.h -KRB
  56. #include "game.h"
  57. #include "scores.h"
  58. #include "modem.h"
  59. #include "object.h"
  60. #include "player.h"
  61. #include "laser.h"
  62. #include "error.h"
  63. #include "collide.h"
  64. #include "endlevel.h"
  65. #include "network.h"
  66. #include "mono.h"
  67. #include "gauges.h"
  68. #include "newmenu.h"
  69. #include "menu.h"
  70. #include "gamesave.h"
  71. #include "netmisc.h"
  72. #include "fuelcen.h"
  73. //#include "commlib.h" -Don't have these either! -KRB
  74. //#include "glfmodem.h" -Don't have these either! -KRB
  75. #include "multi.h"
  76. #include "timer.h"
  77. #include "text.h"
  78. #include "pcx.h"
  79. #include "palette.h"
  80. #include "sounds.h"
  81. #include "digi.h"
  82. #include "multibot.h"
  83. #include "args.h"
  84.  
  85. #include "amiga_serial.h"
  86.  
  87. //This include is just to allow compiling. It doesn't mean it will work. Values in here are only dummy values
  88. //#include "nocomlib.h"
  89.  
  90. #define db_printf(x) /* printf x*/
  91.  
  92. #define MIN_COMM_GAP 8000
  93. #define INIT_STRING_LEN 20
  94. #define LEN_PHONE_NUM_OLD 15
  95. #define LEN_PHONE_NUM   32
  96. #define LEN_PHONE_NAME 12
  97. #define NUM_PHONE_NUM 8
  98.  
  99. // How many times to repeat 'reliable' messages
  100.  
  101. #define EOR_MARK 0xaa
  102.  
  103. #define COM_PROCESS_NORMAL 0
  104. #define COM_PROCESS_ENDLEVEL 1
  105. #define COM_PROCESS_SYNC 2
  106. #define COM_PROCESS_MENU 3
  107.  
  108. #define SELECTION_STARTGAME     1
  109. #define SELECTION_NO_START          2
  110. #define SELECTION_YES_START     3
  111. #define SELECTION_STARTGAME_ABORT   4
  112. #define SELECTION_CLOSE_LINK        5
  113.  
  114. int default_base[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
  115. int default_irq[4] = { 4, 3, 4, 3 };
  116.  
  117. //  Code to support modem/null-modem play
  118.  
  119. // Program determined variables for serial play
  120.  
  121. typedef struct com_sync_pack {
  122.     char type;
  123.     byte proto_version;
  124.     long sync_time;
  125.     byte level_num;
  126.     char difficulty;
  127.     char game_mode;
  128.     char callsign[CALLSIGN_LEN+1];
  129.     short kills[2];
  130.     ushort seg_checksum;
  131. #ifndef SHAREWARE
  132.     byte sync_id;
  133.     char mission_name[9];
  134.     short killed;
  135.     byte game_flags;
  136. #endif
  137.     char    dummy[3]; // Extra space for checksum & sequence number
  138. } com_sync_pack;
  139.  
  140. PORT *com_port;
  141. int serial_active;
  142. int com_baud_rate = 0;
  143. //--unused-- int sync_time = 0;
  144. int com_open = 0;
  145. int got_sync = 0;
  146. int other_got_sync = 0;
  147. int carrier_on = 0;
  148. long com_type = -1; /* What type of UART is available */
  149. static long synccnt;
  150. static ubyte rx_seqnum = 0xff;
  151. static ubyte tx_seqnum = 0;
  152. int OtherPlayer; // Player num for modem opponent
  153. int com_process_mode = COM_PROCESS_NORMAL;
  154. int master = -1; // Am I the master or is the other guy the master?
  155. com_sync_pack my_sync, other_sync;
  156. int start_level_num;
  157.  
  158. int com_custom_port = -1;
  159. int com_custom_irq = -1;
  160. int com_custom_base = -1;
  161.  
  162. int other_menu_choice = 0;
  163.  
  164. int chars_sent = 0;
  165.  
  166. extern short socket_other_valid;
  167. extern char socket_hostname[];
  168.  
  169. // Com buffers
  170.  
  171. static char syncbuffer[MAX_MULTI_MESSAGE_LEN+4];
  172. static char sendbuf[MAX_MULTI_MESSAGE_LEN+4]; // +4 because of +1 for null and +3 for checksum/sequence
  173.  
  174. // Serial setup variables
  175.  
  176. int com_port_num = -1;
  177. int com_speed = -1;
  178. char modem_init_string[INIT_STRING_LEN+1];
  179. char phone_num[NUM_PHONE_NUM+1][LEN_PHONE_NUM+1];
  180. char phone_name[NUM_PHONE_NUM][LEN_PHONE_NAME+1];
  181. short socket_serial = 0;                //  0 use serial, 1 use socket
  182.  
  183. fix  SerialLastMessage = 0;
  184.  
  185. /* Function prototypes for functions not exported through modem.h */
  186.  
  187. void com_param_setup(void);
  188. void com_start_game(void);
  189. void modem_dialout(void);
  190. void modem_answer(void);
  191. int com_sync(int id);
  192. void com_sync_poll(int nitem, newmenu_item *menus, int *key, int citem);
  193.  
  194.  
  195.  
  196. int detect_UART(unsigned baseaddr, int * loc, int * code )
  197. {
  198.     return 4;
  199. }
  200.     
  201.  
  202. int 
  203. com_type_detect()
  204. {
  205. //  static long port;
  206. //  short *ptr;
  207.     int loc, code;
  208.  
  209.     long port_addr[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
  210.     long portaddr;
  211.  
  212.     if (com_type != -1)
  213.         return com_type;
  214.  
  215.     if ( (com_port_num != 0) && (com_port_num != 1) && (com_port_num != 2) && (com_port_num != 3) )
  216.     {
  217.         Int3();
  218.         return -1; // Error, set com_port_num before calling this!  
  219.     }
  220.  
  221.     if (com_port_num == com_custom_port)
  222.         portaddr = com_custom_base;
  223.     else
  224.         portaddr = port_addr[com_port_num];
  225.  
  226.     db_printf(( "com port %x.\n", portaddr));
  227.     
  228.     switch( detect_UART(portaddr, &loc, &code) )    {                                               
  229.     case 0:  // No UART
  230.         db_printf(( "No UART detected. (LOC:%d, CODE:0x%x)\n", loc, code));
  231.         return -1;
  232.     case 1: // 8250
  233.         db_printf(( "UART type is 8250.\n" ));
  234.         return(16450);
  235.     case 2: // 16450 or 8250 with scratch reg.
  236.         db_printf(( "UART is type 16450, or an 8250 with scratch register.\n" ));
  237.         return(16450);
  238.     case 3: // 16550
  239.         db_printf(( "UART is type 16550, with FIFO bug.\n" ));
  240.         return(16450);      // 16550's FIFOs don't work. This is not a typo. (detected 16550, returned 16450 )
  241.     case 4: // 16550A,  which is the only UART the FIFO mode works with.
  242.         db_printf(( "UART is type 16550A, no FIFO bug.\n" ));
  243.         return(16550);
  244.     }
  245.     return (-1);
  246. }
  247.  
  248. #if !defined(NDEBUG) && !defined(NMONO)
  249. void
  250. com_dump_string(char *string)
  251. {
  252.     db_printf(( "%s\n", string));
  253. }
  254. #else
  255. #define com_dump_string()
  256. #endif
  257.  
  258.  
  259. int
  260. com_enable() 
  261. {
  262.     // Detect and enable the COM port selected by the user
  263.  
  264.     int rc;
  265.  
  266.     if (com_open)
  267.         return 0;
  268.  
  269.     rx_seqnum = 0xff;
  270.     tx_seqnum = 0;
  271.  
  272.     // com_port_num and com_speed should be set before calling this func
  273.     com_type = com_type_detect();
  274.  
  275.     if (com_custom_port == com_port_num)
  276.         rc = Change8259Priority(com_custom_irq);
  277.     else if ((com_port_num == COM2) || (com_port_num == COM4))
  278.         rc = Change8259Priority( IRQ3 );
  279.     else
  280.         rc = Change8259Priority( IRQ4 );
  281.  
  282.     if (rc != ASSUCCESS) 
  283.     {
  284.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_SERIAL_OPEN_ERROR);
  285.         return -1;
  286.     }
  287.  
  288. // If our detection is wrong, we want them to be able to go ahead and play anyway.
  289. //  if (com_type == -1)
  290. //  {
  291. //      nm_messagebox(TXT_ERROR, 1, TXT_OK, "Error 2\n%s", TXT_SERIAL_OPEN_ERROR);
  292. //      return -1;
  293. //  }
  294.  
  295.     if (com_port_num == com_custom_port )
  296.     {
  297.         rc = FastSetPortHardware(com_port_num, com_custom_irq, com_custom_base);
  298.         if (rc != ASSUCCESS)
  299.         {
  300.             nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_SERIAL_OPEN_ERROR);
  301.             return -1;
  302.         }
  303.     }
  304.  
  305.     if (com_type == 16550)
  306.     {
  307.         FastSet16550TriggerLevel( TRIGGER_04 );
  308.         FastSet16550UseTXFifos( ON );
  309.     }
  310.  
  311.     FastSavePortParameters(com_port_num);
  312.  
  313.     if (socket_serial == 0) {
  314.         com_port = PortOpenGreenleafFast(com_port_num, com_speed, 'N', 8, 1);
  315.     } else {
  316.         com_port = (PORT *)malloc(sizeof(PORT));
  317.         com_port->status = 1;
  318.         if (socket_open(NULL) > 0)
  319.             com_port->status = 0;
  320.     }
  321.  
  322. #ifndef NDEBUG
  323.     {
  324.         int curr_irq, curr_base;
  325.         //FastGetPortHardware(com_port_num, &curr_irq, &curr_base); //Removed , we don't have this function! -KRB
  326.         db_printf(( "Current port settings: base %x, irq %x.\n", curr_base, curr_irq ));
  327.     }
  328. #endif
  329.  
  330.     if ((com_port == 0) || (com_port->status != 0))
  331.     {
  332.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_SERIAL_OPEN_ERROR);
  333.         return -1;
  334.     }
  335.  
  336.     #ifndef NDEBUG
  337.     db_printf(( "Com port opened.  Status = %d\n", com_port->status));
  338.     #endif
  339.  
  340.     SetDtr(com_port, ON);
  341.     
  342.     if ( FindArg( "-ctsrts" ) || FindArg( "-rtscts" )  )    
  343.         UseRtsCts(com_port, ON); // Now used for null-modem as well, helps IHHD!
  344.     else
  345.         UseRtsCts(com_port, OFF);
  346.  
  347.     com_open = 1;
  348.  
  349.     master = -1;
  350.  
  351. //  DumpPortStatus(com_port, com_dump_string);
  352.  
  353.     return 0;
  354. }
  355.  
  356. void
  357. com_disable()
  358. {
  359.     // close the com port and free associated structures.
  360.  
  361.     int rc;
  362.  
  363.     if (!com_open) 
  364.         return;
  365.  
  366. // SetDtr(com_port, OFF);
  367. //  UseRtsCts(com_port, OFF);
  368.  
  369.     rc = PortClose(com_port);
  370.  
  371.     FastRestorePortParameters(com_port_num);
  372.  
  373.     if (com_custom_port == com_port_num)
  374.     {
  375.         // Custom settings were in effect, roll them back
  376.         rc = FastSetPortHardware(com_port_num, default_irq[com_port_num], default_base[com_port_num]);
  377.     }
  378.  
  379.     if (rc != ASSUCCESS) {
  380.         #ifndef NDEBUG
  381.         db_printf(( "PortClose returned %d!\n", rc));
  382.         #endif
  383.     }
  384.  
  385.     com_port = 0;
  386.     com_open = 0;
  387.  
  388.     master = -1;
  389.  
  390.     #ifndef NDEBUG
  391.     db_printf(( "Com port released.\n"));
  392.     #endif
  393. }
  394.  
  395.  
  396. void
  397. com_abort(void)
  398. {
  399.     // this is the safest way to get out of some modem/serial negotiation
  400.     // and back to the main menu.  Use this whenever this have gone too far
  401.     // awry to repair.
  402.  
  403.     com_disable();
  404.  
  405.     N_players = 0;
  406.  
  407.     change_playernum_to(0);
  408.  
  409.     Viewer = ConsoleObject = &Objects[0];
  410.     Game_mode = GM_GAME_OVER; // Force main menu selection
  411. }
  412.  
  413. void
  414. com_hangup(void)
  415. {
  416.     // Close the serial link
  417.  
  418.     com_send_choice(SELECTION_CLOSE_LINK);
  419.     com_abort();
  420. }
  421.  
  422. void
  423. com_carrier_lost(void)
  424. {
  425.     // Carrier lost, inform and abort
  426.  
  427.     if (multi_in_menu > 0)
  428.     {
  429.         multi_leave_menu = 1;
  430.         return;
  431.     }
  432.  
  433.     Function_mode = FMODE_MENU;
  434.  
  435.     multi_quit_game = 1;
  436.     nm_messagebox(NULL, 1, TXT_OK, TXT_CARRIER_LOST);
  437.     com_abort();
  438. }
  439.  
  440.  
  441. extern ubyte cockpit_mode_save; // From object.c
  442. extern int old_cockpit_mode; // From game.c
  443.  
  444. com_reset_game(void)
  445. {
  446.     int i;
  447.  
  448.     // Reset various parameters before starting a new game
  449.     
  450.     N_players = 2;
  451.  
  452.     for (i = 0; i < N_players; i++)
  453.     {
  454.         Players[i].connected = 1;
  455.     }
  456.  
  457. //  master = -1;
  458.  
  459.     multi_new_game(); // Reset kill list, among other things
  460.     Fuelcen_control_center_destroyed = 0;
  461.     Endlevel_sequence = 0;
  462.     
  463.     // Yes, this really IS as ugly as it gets, kids...
  464.  
  465.     if (Cockpit_mode == CM_LETTERBOX)
  466.     {
  467.         select_cockpit(cockpit_mode_save);
  468.     }
  469.     else if (Cockpit_mode == CM_REAR_VIEW)
  470.     {
  471.         select_cockpit(old_cockpit_mode);
  472.     }
  473. }
  474.  
  475.  
  476. void
  477. com_save_settings(void)
  478. {
  479.     FILE *settings;
  480.     int i;
  481.  
  482.     if ( (settings = fopen("serial.cfg", "wb")) == NULL)
  483.         goto error;
  484.  
  485.     if (fwrite(&com_speed, sizeof(int), 1, settings) != 1)
  486.         goto error;
  487.     
  488.     if (fwrite(&com_port_num, sizeof(int), 1, settings) != 1)
  489.         goto error;
  490.  
  491.     if (fwrite(modem_init_string, 1, INIT_STRING_LEN+1, settings) != INIT_STRING_LEN+1)
  492.         goto error;
  493.  
  494.     for (i = 0; i < NUM_PHONE_NUM; i++)
  495.     {
  496.         if (fwrite(phone_num[i], 1, LEN_PHONE_NUM+1, settings) != LEN_PHONE_NUM+1)
  497.             goto error;
  498.         if (fwrite(phone_name[i], 1, LEN_PHONE_NAME+1, settings) != LEN_PHONE_NAME+1)
  499.             goto error;
  500.     }
  501.  
  502.     if (fwrite(&com_custom_port, sizeof(int), 1, settings) != 1)
  503.         goto error;
  504.     if (fwrite(&com_custom_irq, sizeof(int), 1, settings) != 1)
  505.         goto error;
  506.     if (fwrite(&com_custom_base, sizeof(int), 1, settings) != 1)
  507.         goto error;
  508.     // 100 % success!
  509.  
  510.     fclose(settings);
  511.     return;
  512.  
  513. error:
  514.     nm_messagebox(NULL, 1, TXT_OK, TXT_ERROR_SERIAL_CFG);
  515.  
  516.     if (settings) {
  517.         fclose(settings);
  518.         unlink("serial.cfg");
  519.     }
  520.     
  521.     return;
  522. }
  523.  
  524.  
  525. void
  526. com_load_settings(void)
  527. {
  528.     FILE *settings;
  529.     int i, cfg_size;
  530.  
  531.     if ((settings = fopen("serial.cfg", "rb")) == NULL)
  532.         goto defaults;
  533.  
  534.     cfg_size = filelength(fileno(settings));
  535.  
  536.     // Read the data from the file
  537.     
  538.     if (fread(&com_speed, sizeof(int), 1, settings) != 1)
  539.         goto error;
  540.     if (! ((com_speed == 9600) || (com_speed == 19200) || (com_speed == 38400)) )
  541.         goto error;
  542.  
  543.     if (fread(&com_port_num, sizeof(int), 1, settings) != 1)
  544.         goto error;
  545.     if ( (com_port_num < COM1) || (com_port_num > COM4) )
  546.         goto error;
  547.  
  548.     if (fread(modem_init_string, 1, INIT_STRING_LEN+1, settings) != INIT_STRING_LEN+1)
  549.         goto error;
  550.     modem_init_string[INIT_STRING_LEN] = '\0';
  551.  
  552.     if (cfg_size <= 273 )   {               // Old 15 char LEN_PHONE_NUM's
  553.         db_printf((  "Reading old pre 1.1 phone.cfg\n" ));
  554.         for (i = 0; i < NUM_PHONE_NUM; i++)
  555.         {
  556.             if (fread(phone_num[i], 1, LEN_PHONE_NUM_OLD+1, settings) != LEN_PHONE_NUM_OLD+1)
  557.                 goto error;
  558.             phone_num[i][LEN_PHONE_NUM_OLD] = '\0';
  559.             if (fread(phone_name[i], 1, LEN_PHONE_NAME+1, settings) != LEN_PHONE_NAME+1)
  560.                 goto error;
  561.             phone_name[i][LEN_PHONE_NAME] = '\0';
  562.         }
  563.     } else {            // Normal Phone nums
  564.         for (i = 0; i < NUM_PHONE_NUM; i++)
  565.         {
  566.             if (fread(phone_num[i], 1, LEN_PHONE_NUM+1, settings) != LEN_PHONE_NUM+1)
  567.                 goto error;
  568.             phone_num[i][LEN_PHONE_NUM] = '\0';
  569.             if (fread(phone_name[i], 1, LEN_PHONE_NAME+1, settings) != LEN_PHONE_NAME+1)
  570.                 goto error;
  571.             phone_name[i][LEN_PHONE_NAME] = '\0';
  572.         }
  573.     }
  574.  
  575.     if (fread(&com_custom_port, sizeof(int), 1, settings) != 1) {
  576.         db_printf(( "Reading old file format for serial.cfg.\n"));
  577.         goto close;
  578.     }
  579.  
  580.     if ( (com_custom_port < -1) || (com_custom_port > COM4) )
  581.         goto error;
  582.  
  583.     if (fread(&com_custom_irq, sizeof(int), 1, settings) != 1)
  584.         goto error;
  585.     if ( (com_custom_port < -1) || (com_custom_port > IRQ15) )
  586.         goto error;
  587.  
  588.     if (fread(&com_custom_base, sizeof(int), 1, settings) != 1)
  589.         goto error;
  590.     if (com_custom_base < -1)
  591.         goto error;
  592.  
  593.     //Everything was A-Ok!
  594. close:
  595.     fclose(settings);
  596.  
  597.     return;
  598.  
  599. error:
  600.     nm_messagebox(NULL, 1, TXT_OK, TXT_ERR_SER_SETTINGS);
  601.         
  602. defaults:
  603.     // Return some defaults
  604.     com_speed = 19200; // UART speed
  605.     strcpy(modem_init_string, "ATZ");
  606.     com_port_num = COM2;
  607.     com_custom_port = -1;
  608.     for (i = 0; i < NUM_PHONE_NUM; i++)
  609.     {
  610.         phone_num[i][0] = '\0';
  611.         strcpy(phone_name[i], TXT_EMPTY);
  612.     }
  613.  
  614.     if (settings)
  615.         fclose(settings);
  616.  
  617.     return;
  618. }
  619.  
  620. void
  621. serial_leave_game(void)
  622. {
  623.     #ifndef NDEBUG
  624.     db_printf(( "Called serial_leave_game.\n"));
  625.     #endif
  626. //  com_abort();
  627.     serial_sync_abort(0); // Just in case the other guy is in sync mode
  628.     Game_mode |= GM_GAME_OVER;
  629.     Function_mode = FMODE_MENU;
  630. }
  631.  
  632.  
  633. void
  634. com_send_data(char *ptr, int len, int repeat)
  635. {
  636.     int i;
  637.  
  638.     // Take the raw packet data specified by ptr and append the sequence
  639.     // number and checksum, and pass it to com_send_ptr
  640.  
  641.     if (!com_port)
  642.         return;
  643.  
  644.     if (Game_mode & GM_MODEM)
  645.     {
  646.         i = GetCd(com_port);
  647.         if (i == 0)
  648.             db_printf(( "CARRIER LOST!\n"));
  649.     }
  650.     
  651.     len += 3; // Checksum data is 3 bytes
  652.  
  653.     *(ubyte *)(ptr+(len-3)) = (tx_seqnum+1)%256;
  654.     tx_seqnum = (tx_seqnum+1)%256;
  655.  
  656.     *(ushort *)(ptr+(len-2)) = netmisc_calc_checksum(ptr, len-2);
  657.  
  658.     if (socket_serial == 0) {
  659.         com_send_ptr(ptr, len);
  660.     } else {
  661.         socket_send_ptr(ptr, len);
  662.     }
  663.     if (repeat)
  664.         for (i = 0; i < repeat; i++)
  665.             if (socket_serial == 0) {
  666.                 com_send_ptr(ptr, len);
  667.             } else {
  668.                 socket_send_ptr(ptr, len);
  669.             }
  670. }
  671.  
  672. void old_com_send_ptr(char *ptr, int len)
  673. {
  674.     register    int count;
  675.     register char dat;
  676.  
  677.     for (count = 0, dat=ptr[0]; count < len; dat=ptr[++count])
  678.     {
  679.         WriteChar(com_port, dat);
  680.         if (dat == EOR_MARK)
  681.             WriteChar(com_port, EOR_MARK); // double in-band endmarkers
  682.     }
  683.     WriteChar(com_port, EOR_MARK);  // EOR
  684.     WriteChar(com_port, 0);         // EOR
  685.     chars_sent += len;
  686. }
  687.  
  688.  
  689. void
  690. com_flush()
  691. {
  692.     // Get rid of all waiting data in the serial buffer
  693.  
  694.     int i = 0;
  695.  
  696.     if (!com_open)  
  697.         return;
  698.  
  699.     db_printf(( "COM FLUSH:"));
  700.  
  701.     while (ReadCharTimed(com_port, 100) >= 0)
  702.         i++;
  703.     db_printf(( "%d characters.\n", i));
  704. }
  705.  
  706. int
  707. com_getchar()
  708. {
  709.     register int i;
  710.     static int eor_recv = 0;
  711.  
  712.     // return values:
  713.     //  -1 = Nothing in buffer
  714.     //  -2 = End of record
  715.  
  716.     if (!com_open)
  717.         return(-1);
  718.  
  719.     i = ReadChar(com_port);
  720.  
  721. //  db_printf(( "%c", i));
  722.  
  723.     if (i == ASBUFREMPTY)
  724.         return (-1);
  725.  
  726.     if ((i == EOR_MARK) || eor_recv)
  727.     {
  728.         if (!eor_recv)
  729.             i = ReadChar(com_port);
  730.  
  731.         if (i == ASBUFREMPTY)
  732.         {
  733. //          Assert(eor_recv == 0);
  734.             eor_recv = 1;
  735.             return(-1);
  736.         }
  737.         else if (i == EOR_MARK) 
  738.         {
  739.             eor_recv = 0;
  740.             return(EOR_MARK); // Doubled EOR returns the character
  741.         }
  742.         else
  743.         {
  744. #ifndef NDEBUG
  745.             if (i != 0) {
  746.                 db_printf(( "EOR followed by unexpected value %d.\n", i));
  747.             }
  748. #endif
  749.             eor_recv = 0;
  750.             return(-2);                         
  751.         }
  752.     }
  753.     return(i);
  754. }
  755.  
  756. #define SERIAL_IDLE_TIMEOUT F1_0*10
  757.  
  758.  
  759. void
  760. com_do_frame(void)
  761. {
  762.     static fix last_comm_time = 0;
  763.     static int last_pos_skipped = 0;
  764.     int rval = 0;
  765.  
  766.     if (Endlevel_sequence || (com_process_mode==COM_PROCESS_ENDLEVEL)) {    // Only recieve during endlevel
  767.         int old_Endlevel_sequence = Endlevel_sequence;
  768.         Endlevel_sequence = 1;
  769.         com_process_input();
  770.         Endlevel_sequence = old_Endlevel_sequence;
  771.         return;
  772.     }
  773.  
  774.     last_comm_time += FrameTime;
  775.  
  776.     if ((last_comm_time > MIN_COMM_GAP) || Network_laser_fired)
  777.     {
  778. #ifndef SHAREWARE
  779.         if ((Game_mode & GM_MULTI_ROBOTS) && !last_pos_skipped) {
  780.             rval = multi_send_robot_frame(0);
  781.         }
  782.         if (rval && !Network_laser_fired)
  783.         {
  784.             last_pos_skipped = 1;
  785.             goto skippos;
  786.         }
  787. #endif
  788.         last_pos_skipped = 0;
  789.         multi_send_position(Players[Player_num].objnum);
  790.         multi_send_fire(); // Will return w/o sending if we haven't fired
  791.  
  792. skippos:
  793. //      db_printf(( "%d chars sent, %f cps.\n", chars_sent, f2fl(fixdiv((chars_sent*F1_0),last_comm_time)) ));
  794.         chars_sent = 0;
  795.         last_comm_time = 0;
  796.     }
  797. //  else
  798. //      multi_send_robot_frame(1);
  799.  
  800.     com_process_input();
  801.  
  802.     if (!Fuelcen_control_center_destroyed && (Function_mode == FMODE_GAME) && (SerialLastMessage+SERIAL_IDLE_TIMEOUT < GameTime))
  803.     {
  804.         SerialLastMessage = 0x7fffffff-SERIAL_IDLE_TIMEOUT; // Give no further warnings until next message arrives!
  805.         nm_messagebox(TXT_WARNING, 1, TXT_OK, TXT_CONNECT_LOST, Players[OtherPlayer].callsign);
  806.     }
  807.  
  808.     return;
  809. }
  810.  
  811. int
  812. com_check_message(char *checkbuf, int len)
  813. {
  814.     ushort check;
  815.     ubyte seqnum;
  816.  
  817.  
  818.     if (len < 4)
  819.     {
  820.         #ifndef NDEBUG
  821.         printf(( "message type %d too short to be a real message!\n", checkbuf[0]));
  822.         #endif
  823.         goto error;
  824.     }
  825.  
  826.     if (checkbuf[0] > MULTI_MAX_TYPE)
  827.     {
  828.         #ifndef NDEBUG
  829.         printf( "message type %d out of range.\n", checkbuf[0]);
  830.         #endif
  831.         goto error;
  832.     }
  833.  
  834.     if ( (len-3) != message_length[checkbuf[0]])
  835.     {
  836.         #ifndef NDEBUG
  837.         printf( "message type %d length %d != %d.\n", checkbuf[0], len-3, message_length[checkbuf[0]]);
  838.         #endif
  839.         goto error;
  840.     }
  841.  
  842.     check = netmisc_calc_checksum(checkbuf, len-2);
  843.     if (check != *(ushort *)(checkbuf+(len-2)))
  844.     {
  845.         #ifndef NDEBUG
  846.         printf( "error in message type %d, length %d, checksum %d != %d\n", checkbuf[0], len, check, *(ushort *)(checkbuf+(len-2)));
  847.         #endif
  848.         goto error;
  849.     }
  850.  
  851.     seqnum = checkbuf[(len-3)];
  852.  
  853.     if (seqnum == rx_seqnum)
  854.     {
  855.         return -1;
  856.     }
  857.     
  858.     if (seqnum != (rx_seqnum+1)%256)
  859.     {
  860.         #ifndef NDEBUG
  861.         db_printf(( "Warning, missed 1 or more messages.\n"));
  862.         #endif
  863.     }
  864.     rx_seqnum = seqnum;
  865. //  db_printf(( "message type %d len %d OK!\n", checkbuf[0], len));
  866.     return 0; 
  867.  
  868. error:
  869.     //db_printf(("Line status: %d.\n", GetLineStatus(com_port)));
  870.     //ClearLineStatus(com_port);
  871.     return -1;
  872. }
  873.     
  874.  
  875. void
  876. com_process_menu(char *buf, int len)
  877. {
  878.     char text[80];
  879.  
  880.     len = len;
  881.  
  882.     db_printf(( "com_process_menu: type %d.\n", buf[0]));
  883.  
  884.     switch(buf[0])
  885.     {
  886.         case MULTI_MESSAGE:
  887. #ifndef SHAREWARE
  888.             sprintf(text, "%s %s\n'%s'", Players[OtherPlayer].callsign, TXT_SAYS, buf+2);
  889. #else
  890.             sprintf(text, "%s %s\n'%s'", Players[OtherPlayer].callsign, TXT_SAYS, buf+3);
  891. #endif
  892.             nm_messagebox(NULL, 1, TXT_OK, text);
  893.             break;
  894.         case MULTI_MENU_CHOICE:
  895.             other_menu_choice = buf[1];
  896.             db_printf(( "Other menu choice = %d.\n", other_menu_choice));
  897.             break;
  898.         case MULTI_BEGIN_SYNC:
  899.             // If we get a sync at the menu, send an abort sync, we're not ready yet!
  900.             serial_sync_abort(0);
  901.             break;
  902.     }
  903. }
  904.  
  905. void
  906. com_process_input(void)
  907. {
  908.     // Read all complete messages from the serial buffer and process
  909.     // the contents.  Messages are read into global array snycbuffer.
  910.  
  911.     static int len = 0;
  912.     int entry_com_mode = com_process_mode;
  913.     register    int dat;
  914.  
  915.     if (!com_port)
  916.         return;
  917.  
  918. nextmessage:
  919.     if (Game_mode & GM_MODEM)
  920.     {
  921.         if (!GetCd(com_port))
  922.             com_carrier_lost();
  923.     }
  924.  
  925.     if (!com_port) {
  926.         if (!multi_in_menu) {
  927.             multi_quit_game = 1;
  928.         }
  929.         else {
  930.             multi_leave_menu = 1;
  931.         }
  932.     }
  933.  
  934.     if (com_process_mode != entry_com_mode)
  935.     {
  936. //      db_printf(( "Exiting com_process_input due to mode switch.\n"));
  937.         return;
  938.     }
  939. #if 0
  940.     while ( (len <= MAX_MULTI_MESSAGE_LEN) && (dat = com_getchar()) > -1) // Returns -1 when serial pipe empty
  941.     {
  942.         syncbuffer[len++] = dat;
  943.     }
  944. #endif
  945.  
  946.     len = MAX_MULTI_MESSAGE_LEN+4;
  947.  
  948.     if (socket_serial == 0) {
  949.         dat = com_receive_ptr(syncbuffer, &len);
  950.     } else {
  951.         dat = socket_receive_ptr(syncbuffer, &len);
  952.     }
  953.  
  954.     if ((dat == -2) || (len > MAX_MULTI_MESSAGE_LEN)) // Returns -2 when end of message reached
  955.     {
  956.         // End of message
  957.         SerialLastMessage = GameTime;
  958.  
  959.         if (!com_check_message(syncbuffer, len))
  960.         {
  961.             switch(com_process_mode)
  962.             {
  963.                 case COM_PROCESS_NORMAL:
  964.                 case COM_PROCESS_ENDLEVEL:
  965.                     multi_process_data(syncbuffer, len); break;
  966.                 case COM_PROCESS_MENU:
  967.                     if (!Endlevel_sequence) com_process_menu(syncbuffer, len); break;
  968.                 case COM_PROCESS_SYNC:
  969.                     if (!Endlevel_sequence) com_process_sync(syncbuffer, len); break;
  970.                 default:
  971.                     Int3(); // Bad com_process_mode switch set!
  972.             }
  973.         }
  974.         len = 0;
  975.         goto nextmessage;
  976.     }
  977.     if (dat == -3) // Returns -3 when carrier lost
  978.     {
  979.         com_abort();
  980.         len = 0;
  981.     }
  982.     return ;
  983. }
  984.  
  985. int
  986. com_connect()
  987. {
  988.     my_sync.type = MULTI_BEGIN_SYNC;
  989.     my_sync.difficulty = 0;
  990.     memcpy(my_sync.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
  991.     my_sync.seg_checksum = 0;
  992.     my_sync.game_mode = Game_mode;
  993.     my_sync.level_num = 0;
  994.                                  
  995.     #ifndef NDEBUG
  996.     db_printf(( "com_connect()\n"));
  997.     #endif
  998.  
  999.     if(com_sync(-1))
  1000.         return(-1); // Failure in sync
  1001.  
  1002.     if (master == -1)
  1003.     {
  1004.         #ifndef NDEBUG
  1005.         db_printf(( "My rand = %d, other rand = %d.\n", my_sync.sync_time, other_sync.sync_time));
  1006.         #endif
  1007.  
  1008.         // Figure out who is the master
  1009.         if (my_sync.sync_time > other_sync.sync_time)
  1010.         {
  1011.             db_printf(( "Swtiching player to master.\n"));
  1012.             master=1;
  1013.             change_playernum_to(0);
  1014.         }
  1015.         else if (my_sync.sync_time < other_sync.sync_time)
  1016.         {
  1017.             db_printf(( "Switching player to slave.\n"));
  1018.             master = 0;
  1019.             change_playernum_to(1);
  1020.         }
  1021.         else
  1022.             return(-1);  // Didn't sync properly, try again
  1023.     }
  1024.     
  1025.     // Copy the remote sync data into local variables
  1026.     
  1027.     OtherPlayer = (Player_num+1)%2;
  1028.     db_printf(( "Other player is #%d.\n", OtherPlayer));
  1029.     memcpy(Players[OtherPlayer].callsign, other_sync.callsign, CALLSIGN_LEN+1);
  1030.  
  1031.     return(0);
  1032. }
  1033.  
  1034. #define ADD_ITEM(t,value,key)  do { m[num_options].type=NM_TYPE_MENU; menu_choice[num_options]=value; m[num_options].text=t; num_options++; } while (0)
  1035.  
  1036. #define MENU_MODEM_CALL             0
  1037. #define MENU_MODEM_ANSWER           1
  1038. #define MENU_SERIAL_LINK_START  2
  1039. #define MENU_SERIAL_SETUP           3
  1040. #define MENU_MODEM_HANGUP           4
  1041. #define MENU_SERIAL_GAME_START  5
  1042. #define MENU_SEND_MESSAGE           6
  1043.  
  1044.  
  1045. void
  1046. com_menu_poll(int nitems, newmenu_item *menus, int *key, int citem)
  1047. {
  1048.     // Watch the serial stream if we are connected and take appropriate actions
  1049.  
  1050.     int old_game_mode;
  1051.  
  1052.     menus = menus;
  1053.     citem = citem;
  1054.     nitems = nitems;
  1055.  
  1056.     if (! ( (Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM) ) )
  1057.         return;
  1058.  
  1059.     com_process_mode = COM_PROCESS_MENU;
  1060.     old_game_mode = Game_mode;
  1061.     other_menu_choice = 0;  
  1062.  
  1063.     com_process_input();
  1064.  
  1065.     if ((old_game_mode != Game_mode) || other_menu_choice || (com_process_mode != COM_PROCESS_MENU))
  1066.         *key = -2;
  1067.     if (multi_leave_menu)
  1068.         *key = -2;
  1069. }
  1070.  
  1071. void
  1072. com_send_choice(int choice)
  1073. {
  1074.     sendbuf[0] = (char)MULTI_MENU_CHOICE;
  1075.     sendbuf[1] = (char)choice;
  1076.  
  1077.     com_send_data(sendbuf, 2, 1);
  1078. }
  1079.  
  1080. void
  1081. com_ready_to_start(void)
  1082. {
  1083.     newmenu_item m[2];
  1084.     int choice;
  1085.  
  1086.     m[0].type = m[1].type = NM_TYPE_MENU;
  1087.     m[0].text = TXT_YES;
  1088.     m[1].text = TXT_NO;
  1089.  
  1090.     choice = newmenu_do1(NULL, TXT_READY_DESCENT, 2, m, com_menu_poll, 0 );
  1091.     if (choice == 0)
  1092.     {
  1093.         // Yes
  1094.         com_send_choice(SELECTION_YES_START);
  1095.         other_menu_choice = SELECTION_STARTGAME;
  1096.         com_start_game();
  1097.     }       
  1098.     else 
  1099.     {
  1100.         com_send_choice(SELECTION_NO_START);
  1101.     }
  1102. }
  1103.  
  1104. void
  1105. com_process_other_menu_choice(void)
  1106. {
  1107.     if (other_menu_choice == SELECTION_STARTGAME)   
  1108.         com_ready_to_start();
  1109.     else if (other_menu_choice == SELECTION_CLOSE_LINK) 
  1110.     {
  1111.         nm_messagebox(NULL, 1, TXT_OK, TXT_CLOSED_LINK);
  1112.         com_hangup();
  1113.     }
  1114. }
  1115.  
  1116. #define SUBTITLE_LEN 120
  1117.  
  1118. void
  1119. com_main_menu(void)
  1120. {
  1121.     newmenu_item m[10];
  1122.     newmenu_item n[1];
  1123.     int menu_choice[10];
  1124.     int num_options = 0;
  1125.     int choice=0, ch = 0;
  1126.     int old_game_mode;
  1127.     char subtitle[SUBTITLE_LEN];
  1128.     int pcx_error;
  1129.     int socket_error;
  1130.  
  1131.     if (com_port_num == -1)
  1132.         com_load_settings();
  1133.  
  1134.     setjmp(LeaveGame);
  1135.  
  1136.     gr_set_current_canvas(NULL);
  1137.     pcx_error = pcx_read_bitmap(Menu_pcx_name,&grd_curcanv->cv_bitmap,grd_curcanv->cv_bitmap.bm_type,NULL);
  1138.     Assert(pcx_error == PCX_ERROR_NONE);
  1139.  
  1140.     com_process_mode = COM_PROCESS_MENU;
  1141.  
  1142. newmenu:
  1143.     num_options = 0;
  1144.  
  1145.     if (! ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)) )
  1146.     {
  1147.         // We haven't established any type of link
  1148.   /*      ADD_ITEM(TXT_DIAL_MODEM, MENU_MODEM_CALL, KEY_D);
  1149.         ADD_ITEM(TXT_ANSWER_MODEM, MENU_MODEM_ANSWER, KEY_A);
  1150.         ADD_ITEM(TXT_NULL_MODEM, MENU_SERIAL_LINK_START, KEY_E);
  1151.         ADD_ITEM(TXT_COM_SETTINGS, MENU_SERIAL_SETUP, KEY_C);*/
  1152.         if (serial_active & 1) {
  1153.             ADD_ITEM("Start serial link", MENU_SERIAL_LINK_START, KEY_S);
  1154.             ADD_ITEM("Com settings", MENU_SERIAL_SETUP, KEY_C);
  1155.         }
  1156.         if (serial_active & 2) {
  1157.             ADD_ITEM("Start TCP/IP link", 20, KEY_T);
  1158.             ADD_ITEM("TCP/IP settings", 21, KEY_T);
  1159.         }
  1160.     }
  1161.     else
  1162.     {
  1163.         ADD_ITEM(TXT_START_GAME, MENU_SERIAL_GAME_START, KEY_S);
  1164.         ADD_ITEM(TXT_SEND_MESSAGEP, MENU_SEND_MESSAGE, KEY_S);
  1165.     }
  1166.     if (Game_mode & GM_MODEM)
  1167.         ADD_ITEM(TXT_HANGUP_MODEM, MENU_MODEM_HANGUP, KEY_H);
  1168.     
  1169.     if (Game_mode & GM_SERIAL)
  1170.         ADD_ITEM(TXT_CLOSE_LINK, MENU_MODEM_HANGUP, KEY_C);
  1171.  
  1172.     sprintf(subtitle, "%s\n\n", "Head to head");
  1173.  
  1174.     if (Game_mode & GM_SERIAL)
  1175.         sprintf(subtitle+strlen(subtitle), "%s %s\n%s", TXT_SERIAL, TXT_LINK_ACTIVE, Players[OtherPlayer].callsign);
  1176.     else if (Game_mode & GM_MODEM)
  1177.         sprintf(subtitle+strlen(subtitle), "%d %s %s %s\n%s", com_baud_rate, TXT_BAUD, TXT_MODEM, TXT_LINK_ACTIVE, Players[OtherPlayer].callsign);  
  1178.     else
  1179.         sprintf(subtitle+strlen(subtitle), TXT_NOT_CONNECTED);
  1180.  
  1181.     multi_leave_menu = 0;
  1182.  
  1183.  
  1184.     Assert(strlen(subtitle) < SUBTITLE_LEN);
  1185.  
  1186.     choice = newmenu_do1(NULL, subtitle, num_options, m, com_menu_poll, 0);
  1187.  
  1188.     db_printf(( "main menu choice was %d.\n", choice));
  1189.  
  1190.     if (choice == -1)
  1191.     {
  1192.         if (!((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)))
  1193.         {
  1194.             com_disable();
  1195.             return;
  1196.         }
  1197.         m[0].text = TXT_YES; m[1].text = TXT_NO;
  1198.         m[0].type = m[1].type = NM_TYPE_MENU;
  1199.  
  1200.         choice = newmenu_do1(NULL, TXT_EXIT_WILL_CLOSE, 2, m, com_menu_poll, 0);
  1201.         if (choice == 0)
  1202.         {
  1203.             com_send_choice(SELECTION_CLOSE_LINK);
  1204.             com_hangup();
  1205.             return;
  1206.         }
  1207.         if ((choice == -2) && (other_menu_choice))
  1208.             com_process_other_menu_choice();
  1209.  
  1210.         goto newmenu;
  1211.     }
  1212.  
  1213.     if (choice == -2)
  1214.     {
  1215.         // Menu poll loop caused a re-draw
  1216.         if (other_menu_choice == SELECTION_STARTGAME)   
  1217.             com_ready_to_start();
  1218.         else if (other_menu_choice == SELECTION_CLOSE_LINK) 
  1219.         {
  1220.             nm_messagebox(NULL, 1, TXT_OK, TXT_CLOSED_LINK);
  1221.             com_hangup();
  1222.         }
  1223.             
  1224.         if (Function_mode == FMODE_GAME)
  1225.             return; 
  1226.  
  1227.         if (!com_port)
  1228.             Game_mode = GM_GAME_OVER;
  1229.  
  1230.         goto newmenu;
  1231.     }       
  1232.  
  1233.     if (choice > -1) 
  1234.     {
  1235.         old_game_mode=Game_mode;
  1236.         switch (menu_choice[choice])
  1237.         {
  1238.             case MENU_SERIAL_SETUP:
  1239.                 com_param_setup();
  1240.                 goto newmenu;
  1241.                 break;
  1242.             case MENU_SERIAL_GAME_START:
  1243.                 com_start_game();
  1244.                 if (Function_mode != FMODE_GAME) 
  1245.                     goto newmenu;
  1246.                 break;
  1247.             case 20:    // tcp start
  1248.                 n[0].type = NM_TYPE_TEXT;
  1249.                 n[0].text = "Connecting";
  1250. //                nm_messagebox("Connecting", 1
  1251.                 socket_serial = 1;
  1252.                 socket_error = socket_open(socket_hostname);
  1253.                 if (socket_error <= 0) {
  1254.                     switch (socket_error) {
  1255.                         case 0:
  1256.                             nm_messagebox("Error", 1, TXT_OK, "No host to connect to");
  1257.                             goto newmenu;
  1258.                             break;
  1259.                         case -1:
  1260.                             nm_messagebox("Error", 1, TXT_OK, "Can`t create socket");
  1261.                             goto newmenu;
  1262.                             break;
  1263.                         case -2:
  1264.                             nm_messagebox("Error", 1, TXT_OK, "Can`t bind port");
  1265.                             goto newmenu;
  1266.                             break;
  1267.                         case -3:
  1268.                             nm_messagebox("Error", 1, TXT_OK, "Can`t connect");
  1269.                             goto newmenu;
  1270.                             break;
  1271.                         case -4:
  1272.                             nm_messagebox("Error", 1, TXT_OK, "Unknown host");
  1273.                             goto newmenu;
  1274.                             break;
  1275.                         default:
  1276.                             nm_messagebox("Error", 1, TXT_OK, "Unknown error");
  1277.                             goto newmenu;
  1278.                             break;
  1279.                     }
  1280.                 }
  1281.                 serial_link_start();
  1282.                 goto newmenu;
  1283.                 break;
  1284.             case 21:    //  tcp config
  1285.                 socket_param_setup();
  1286.                 goto newmenu;
  1287.                 break;
  1288.             case MENU_MODEM_CALL:
  1289.                 modem_dialout();
  1290.                 goto newmenu;
  1291.                 break;
  1292.             case MENU_MODEM_ANSWER:
  1293.                 modem_answer();
  1294.                 goto newmenu;
  1295.                 break;
  1296.             case MENU_SEND_MESSAGE:
  1297.                 multi_send_message_dialog();
  1298.                 if (Network_message_reciever != -1)
  1299.                     multi_send_message();
  1300.                 multi_sending_message = 0;
  1301.                 goto newmenu;
  1302.                 break;
  1303.             case MENU_SERIAL_LINK_START:
  1304.                 socket_serial = 0;
  1305.                 serial_link_start();
  1306.                 goto newmenu;
  1307.                 break;
  1308.             case MENU_MODEM_HANGUP:
  1309.                 com_hangup();
  1310.                 if (socket_serial == 0) {
  1311.                     amiserial_close();
  1312.                 } else {
  1313.                     socket_close();
  1314.                 }
  1315.                 goto newmenu;
  1316.                 break;
  1317.             default: 
  1318.                 Int3();
  1319.                 return;
  1320.         }
  1321.     }
  1322. }
  1323.  
  1324.  
  1325. void com_custom_param_setup(void)
  1326. {
  1327.     // User menu for setting up custom IRQ/Base settings for a COM port
  1328.  
  1329.     newmenu_item mm[6];
  1330.     int loc;
  1331.  
  1332.     char base[10]; 
  1333.     char irq[3];
  1334.     char title[60];
  1335.     int new_irq, new_base;
  1336.     int menu_save, menu_reset;
  1337.     int mmn;
  1338.  
  1339.     sprintf(title, "%s%d", TXT_COM_CUSTOM_SETTINGS, com_port_num+1);
  1340.     
  1341.     if (com_port_num != com_custom_port) 
  1342.     {
  1343.         new_irq = default_irq[com_port_num];
  1344.         new_base = default_base[com_port_num];
  1345.     }
  1346.     else
  1347.     {
  1348.         new_irq = com_custom_irq;
  1349.         new_base = com_custom_base;
  1350.     }
  1351.  
  1352. newmenu:
  1353.     sprintf(base, "%x", new_base);
  1354.     sprintf(irq, "%d", new_irq);
  1355.  
  1356.     loc = 0;
  1357.     mm[loc].type = NM_TYPE_TEXT; mm[loc].text = TXT_COM_BASE; loc++;
  1358.     mm[loc].type = NM_TYPE_INPUT; mm[loc].text = base; mm[loc].text_len = 9; loc++;
  1359.     mm[loc].type = NM_TYPE_TEXT; mm[loc].text = TXT_COM_IRQ; loc++;
  1360.     mm[loc].type = NM_TYPE_INPUT; mm[loc].text = irq, mm[loc].text_len = 2; loc++;
  1361.     menu_reset = loc;
  1362.     mm[loc].type = NM_TYPE_MENU; mm[loc].text = TXT_RESET_DEFAULTS; loc++;
  1363.     menu_save = loc;
  1364.     mm[loc].type = NM_TYPE_MENU; mm[loc].text = TXT_ACCEPT; loc++;  
  1365.  
  1366.     mmn = newmenu_do1(NULL, title, loc, mm, NULL, menu_save);
  1367.  
  1368.     if (mmn == -1)
  1369.         return; // All changes lost
  1370.  
  1371.     new_irq = strtol(irq, NULL, 0);
  1372.     new_base = strtol(base, NULL, 16);
  1373.  
  1374.     if (mmn == menu_reset) 
  1375.     {
  1376.         new_irq = default_irq[com_port_num];
  1377.         new_base = default_base[com_port_num];
  1378.     }
  1379.     if (mmn == menu_save) 
  1380.     {
  1381.         if ((new_irq == default_irq[com_port_num]) && (new_base == default_base[com_port_num])) {
  1382.             com_custom_port = -1;
  1383.             db_printf(( "Custom com settings not changed.\n"));
  1384.             return;
  1385.         }
  1386.         if ((new_irq < IRQ2) || (new_irq > IRQ7)) {
  1387.            new_irq = default_irq[com_port_num];
  1388.             nm_messagebox(NULL, 1, TXT_OK, TXT_VALID_IRQS);
  1389.             goto newmenu;
  1390.         }
  1391.  
  1392.         com_custom_irq = new_irq;
  1393.         com_custom_base = new_base;
  1394.         com_custom_port = com_port_num;
  1395.         return;
  1396.     }
  1397.     goto newmenu;
  1398. }
  1399.  
  1400. void com_param_setup_poll(int nitems, newmenu_item *menus, int *key, int citem)
  1401. {
  1402.     nitems = nitems;
  1403.     key = key;
  1404.     citem = citem;
  1405.     
  1406.     if ((com_custom_port == -1) && menus[4].value)
  1407.     {
  1408.         menus[4].value = 0; menus[4].redraw = 1;
  1409.         return;
  1410.     }
  1411.  
  1412.     if (com_custom_port == -1)
  1413.         return;
  1414.  
  1415.     if (menus[com_custom_port].value && !menus[4].value) 
  1416.     {
  1417.         menus[4].value = 1; menus[4].redraw = 1;
  1418.     }
  1419.     else if (menus[4].value && !menus[com_custom_port].value)
  1420.     {
  1421.         menus[4].value = 0; menus[4].redraw = 1;
  1422.     }
  1423.     
  1424. }
  1425.  
  1426. void old_com_param_setup(void)
  1427. {
  1428.     int mmn;
  1429.     int was_enabled = 0;
  1430.     newmenu_item mm[12];
  1431.     char init_string[INIT_STRING_LEN+1];
  1432.     int changed = 0;
  1433.     int menu_baud, menu_custom, menu_save;
  1434.     int loc;
  1435.  
  1436.     strcpy (init_string, modem_init_string);
  1437.  
  1438.     com_type = -1;
  1439.  
  1440.     if (com_open)
  1441.     {
  1442.         was_enabled = 1;
  1443.         com_disable();
  1444.     }
  1445.  
  1446. setupmenu:  
  1447.     loc = 0;
  1448.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_port_num == COM1); mm[loc].text="COM1"; mm[loc].group=0; loc++;
  1449.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_port_num == COM2); mm[loc].text="COM2"; mm[loc].group=0; loc++;
  1450.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_port_num == COM3); mm[loc].text="COM3"; mm[loc].group=0; loc++;
  1451.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_port_num == COM4); mm[loc].text="COM4"; mm[loc].group=0; loc++;
  1452.     menu_custom = loc;
  1453.     mm[loc].type=NM_TYPE_CHECK; mm[loc].value=(com_port_num == com_custom_port); mm[loc].text=TXT_COM_CUSTOM_SETTINGS; loc++;
  1454.     mm[loc].type=NM_TYPE_TEXT; mm[loc].text = TXT_BAUD_RATE; loc++;
  1455.     menu_baud = loc;
  1456.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_speed == 9600); mm[loc].text="9600"; mm[loc].group=1; loc++;
  1457.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_speed == 19200); mm[loc].text="19200"; mm[loc].group=1; loc++;
  1458.     mm[loc].type=NM_TYPE_RADIO; mm[loc].value=(com_speed == 38400); mm[loc].text="38400"; mm[loc].group=1; loc++;
  1459.     mm[loc].type=NM_TYPE_TEXT; mm[loc].text = TXT_MODEM_INIT_STRING; loc++;
  1460.     mm[loc].type=NM_TYPE_INPUT; mm[loc].text_len = INIT_STRING_LEN; mm[loc].text = init_string; loc++;
  1461.     menu_save = loc;
  1462.     mm[loc].type=NM_TYPE_MENU; mm[loc].text = TXT_ACCEPT_SAVE; loc++;
  1463.  
  1464.     mmn = newmenu_do1(NULL, TXT_SERIAL_SETTINGS, loc, mm, com_param_setup_poll, menu_save);
  1465.  
  1466.     if (mmn > -1 ) {
  1467.         changed = 1;
  1468.  
  1469.         if (mm[0].value)
  1470.             com_port_num = COM1;
  1471.         else if (mm[1].value)
  1472.             com_port_num = COM2;
  1473.         else if (mm[2].value) 
  1474.             com_port_num = COM3;
  1475.         else 
  1476.             com_port_num = COM4;
  1477.         
  1478.         if (mmn == menu_custom)
  1479.         {
  1480.             com_custom_param_setup();
  1481.         }
  1482.  
  1483.         com_type = -1;
  1484.         com_type = com_type_detect();
  1485.  
  1486.         if (com_type == -1)
  1487.         {
  1488.             nm_messagebox(NULL, 1, TXT_OK, "%s\n%s", TXT_WARNING, TXT_NO_UART);
  1489.         }
  1490.  
  1491.         if ((mm[menu_baud].value) || (mmn == menu_baud)) 
  1492.             com_speed = 9600;
  1493.         else if ((mm[menu_baud+1].value) || (mmn == menu_baud+1))
  1494.             com_speed = 19200;
  1495.         else
  1496.         {
  1497.             if (com_type == 16550)
  1498.                 com_speed = 38400;
  1499.             else
  1500.             {
  1501.                 nm_messagebox(NULL, 1, TXT_OK, TXT_WARNING_16550);
  1502.                 com_speed = 19200;
  1503.             }
  1504.         }
  1505.                 
  1506.         //db_printf(( "%s\n", init_string));
  1507.  
  1508.         if ((strnicmp("AT", init_string, 2)) && (strlen(init_string) < (INIT_STRING_LEN-2)))
  1509.             sprintf(modem_init_string, "AT%s", init_string);
  1510.         else
  1511.             strcpy(modem_init_string, init_string);
  1512.  
  1513.         if (mmn != menu_save)
  1514.             goto setupmenu;
  1515.     }
  1516.     
  1517.     if (was_enabled)
  1518.         com_enable();
  1519.  
  1520.     if (changed)
  1521.         com_save_settings();
  1522.  
  1523. }
  1524.     
  1525.  
  1526. extern int opt_cinvul;
  1527. extern int last_cinvul;
  1528.  
  1529. void modem_game_param_poll( int nitems, newmenu_item * menus, int * key, int citem )
  1530. {
  1531.     nitems = nitems;
  1532.     key = key;
  1533.     citem = citem;
  1534.     if ( last_cinvul != menus[opt_cinvul].value )   {
  1535.         sprintf( menus[opt_cinvul].text, "%s: %d %s", TXT_REACTOR_LIFE, menus[opt_cinvul].value*5, TXT_MINUTES_ABBREV );
  1536.         last_cinvul = menus[opt_cinvul].value;
  1537.         menus[opt_cinvul].redraw = 1;
  1538.     }       
  1539. }
  1540.  
  1541. // Handshaking to start a serial game, 2 players only
  1542.  
  1543. int com_start_game_menu(void)
  1544. {
  1545.     newmenu_item m[13];
  1546.     char level[5];
  1547.     int choice = 0;
  1548.     int opt, diff_opt, mode_opt, options_opt;
  1549.     char level_text[32];
  1550.     char srinvul[32];
  1551.  
  1552. #ifndef SHAREWARE
  1553.     int new_mission_num, anarchy_only = 0;
  1554.  
  1555.     new_mission_num = multi_choose_mission(&anarchy_only);
  1556.  
  1557.     if (new_mission_num < 0)
  1558.         return 0;
  1559.  
  1560.     strcpy(my_sync.mission_name, Mission_list[new_mission_num].filename);
  1561. #endif
  1562.  
  1563.     sprintf(level, "1");
  1564.  
  1565.     Game_mode &= ~GM_MULTI_COOP;
  1566.     Game_mode &= ~GM_MULTI_ROBOTS;
  1567.     Netgame.game_flags = 0;
  1568.  
  1569.     sprintf(level_text, "%s (1-%d)", TXT_LEVEL_, Last_level);
  1570.     if (Last_secret_level < -1)
  1571.         sprintf(level_text+strlen(level_text)-1, ", S1-S%d)", -Last_secret_level);
  1572.     else if (Last_secret_level == -1)
  1573.         sprintf(level_text+strlen(level_text)-1, ", S1)");
  1574.  
  1575.     Assert(strlen(level_text) < 32);
  1576.  
  1577.     // Put up menu for user choices controlling gameplay
  1578.  
  1579. newmenu:
  1580.     opt = 0;
  1581.     m[opt].type = NM_TYPE_TEXT; m[opt].text = level_text; opt++;
  1582.     m[opt].type = NM_TYPE_INPUT; m[opt].text_len = 4; m[opt].text = level; opt++;
  1583. #ifdef ROCKWELL_CODE
  1584.     mode_opt = 0;
  1585. #else
  1586.     m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_MODE;
  1587.     mode_opt = opt; 
  1588.     m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY; m[opt].value=!(Game_mode & GM_MULTI_ROBOTS); m[opt].group = 0; opt++;
  1589.     m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY_W_ROBOTS; m[opt].value=(!(Game_mode & GM_MULTI_COOP) && (Game_mode & GM_MULTI_ROBOTS)); m[opt].group = 0; opt++;
  1590.     m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_COOPERATIVE; m[opt].value=(Game_mode & GM_MULTI_COOP);m[opt].group = 0; opt++;
  1591. #endif
  1592.     diff_opt = opt;
  1593.     m[opt].type = NM_TYPE_SLIDER; m[opt].text = TXT_DIFFICULTY; m[opt].value = Player_default_difficulty; m[opt].min_value = 0; m[opt].max_value = (NDL-1); opt++;
  1594.  
  1595. #ifndef SHAREWARE
  1596.     options_opt = opt;
  1597. //  m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_IDS; m[opt].value=0; opt++;
  1598.     m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_ON_MAP; m[opt].value=0; opt++;
  1599.  
  1600.     opt_cinvul = opt;
  1601.     sprintf( srinvul, "%s: %d %s", TXT_REACTOR_LIFE, 5*control_invul_time, TXT_MINUTES_ABBREV );
  1602.     last_cinvul = control_invul_time;
  1603.     m[opt].type = NM_TYPE_SLIDER; m[opt].value=control_invul_time; m[opt].text= srinvul; m[opt].min_value=0; m[opt].max_value=15; opt++;
  1604.  
  1605. #endif
  1606.  
  1607.     Assert(opt <= 13);
  1608.  
  1609.     choice = newmenu_do1(NULL, TXT_SERIAL_GAME_SETUP, opt, m, modem_game_param_poll, 1);
  1610.     if (choice > -1) 
  1611.     {
  1612. #ifdef ROCKWELL_CODE
  1613.         Game_mode |= (GM_MULTI_COOP | GM_MULTI_ROBOTS);
  1614. #else
  1615.         if (m[mode_opt].value)
  1616.             Game_mode &= ~(GM_MULTI_COOP | GM_MULTI_ROBOTS);
  1617. #ifdef SHAREWARE
  1618.         else {
  1619.             nm_messagebox(NULL, 1, TXT_OK, TXT_ONLY_ANARCHY);
  1620.             goto newmenu;
  1621.         }
  1622. #else
  1623.         else if (anarchy_only) {
  1624.             nm_messagebox(NULL, 1, TXT_OK, TXT_ANARCHY_ONLY_MISSION);
  1625.             goto newmenu;
  1626.         }
  1627.         else if (m[mode_opt+1].value)
  1628.         {
  1629.             Game_mode &= ~GM_MULTI_COOP;
  1630.             Game_mode |= GM_MULTI_ROBOTS;
  1631.         }
  1632.         else
  1633.             Game_mode |= (GM_MULTI_COOP | GM_MULTI_ROBOTS);
  1634. #endif
  1635. #endif  // ifdef ROCKWELL_CODE
  1636.  
  1637. //      if (m[options_opt].value)
  1638. //          Netgame.game_flags |= NETGAME_FLAG_SHOW_ID;
  1639.         if (m[options_opt].value)
  1640.             Netgame.game_flags |= NETGAME_FLAG_SHOW_MAP;
  1641.         if (!strnicmp(level, "s", 1))
  1642.             start_level_num = -atoi(level+1);
  1643.         else
  1644.             start_level_num = atoi(level);
  1645.  
  1646.         if ((start_level_num < Last_secret_level) || (start_level_num > Last_level) || (start_level_num == 0))
  1647.         {
  1648.             nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_LEVEL_OUT_RANGE);
  1649.             sprintf(level, "1");
  1650.             goto newmenu;
  1651.         }
  1652.  
  1653.         Difficulty_level = m[diff_opt].value;
  1654.         control_invul_time = m[opt_cinvul].value;
  1655.         Netgame.control_invul_time = control_invul_time*5*F1_0*60;
  1656.  
  1657.         return(1); // Go for game!
  1658.     }
  1659.     return 0; // No game
  1660. }
  1661.  
  1662. int
  1663. com_ask_to_start()
  1664. {   
  1665.     // Ask the other player if its OK to start now
  1666.  
  1667.     newmenu_item m[1];
  1668.     int choice;
  1669.  
  1670.     com_send_choice(SELECTION_STARTGAME);
  1671.  
  1672.     m[0].type = NM_TYPE_TEXT; m[0].text = TXT_ESC_ABORT;
  1673. menu:
  1674.     choice = newmenu_do(NULL, TXT_WAIT_FOR_OK, 1, m, com_menu_poll);
  1675.  
  1676.     if (choice == -1)
  1677.     {
  1678.         com_send_choice(SELECTION_STARTGAME_ABORT);
  1679.         return(0);
  1680.     }
  1681.     if (choice == -2)
  1682.     {
  1683.         if (other_menu_choice == SELECTION_YES_START)
  1684.             return(1);
  1685.         else if (other_menu_choice == SELECTION_STARTGAME)
  1686.         {
  1687.             com_send_choice(SELECTION_YES_START);
  1688.             return(1);
  1689.         }
  1690.         else 
  1691.             return(0);
  1692.     }
  1693.     goto menu;
  1694. }
  1695.         
  1696.  
  1697. void
  1698. com_start_game()
  1699. {
  1700.     // Start a serial game after being linked
  1701.  
  1702.     db_printf(( "Entered com_start_game\n"));
  1703.  
  1704.     com_reset_game();
  1705.  
  1706.     db_printf(( "Game mode is %x\n", Game_mode));
  1707.  
  1708.     if (! ( (Game_mode & GM_MODEM) || (Game_mode & GM_SERIAL) ) ) 
  1709.         return;
  1710.     
  1711.     Assert (master != -1);
  1712.  
  1713.     if (other_menu_choice != SELECTION_STARTGAME)
  1714.     {
  1715.         if (!com_ask_to_start())
  1716.             return;
  1717.     }
  1718.  
  1719.     if (master == 1) // Master chooses options
  1720.     {
  1721.         if (com_start_game_menu())
  1722.         {
  1723.             OtherPlayer = 1;
  1724.             change_playernum_to(0);
  1725.             my_sync.level_num = start_level_num;
  1726.             my_sync.difficulty = Difficulty_level;
  1727.             my_sync.game_mode = Game_mode;
  1728.             memcpy(my_sync.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
  1729. #ifndef SHAREWARE
  1730.             my_sync.sync_time = control_invul_time*5*F1_0*60;
  1731.             my_sync.game_flags = Netgame.game_flags;
  1732.             Netgame.control_invul_time = control_invul_time*5*F1_0*60;
  1733. #endif
  1734.             com_sync(0);
  1735.         }
  1736.     }
  1737.     else // Slave
  1738.     {
  1739.         OtherPlayer = 0;
  1740.         change_playernum_to(1);
  1741.         memcpy(my_sync.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
  1742.     
  1743.         my_sync.level_num = 1;
  1744.         
  1745.         com_sync(0);
  1746.         if (com_process_mode == COM_PROCESS_NORMAL)
  1747.         {
  1748.             Difficulty_level = other_sync.difficulty;
  1749.             start_level_num = other_sync.level_num;
  1750.             Game_mode = (unsigned char)other_sync.game_mode & 0xff;
  1751. #ifndef SHAREWARE
  1752.             Netgame.game_flags = other_sync.game_flags;
  1753.             Netgame.control_invul_time = other_sync.sync_time;
  1754.             if (!load_mission_by_name(other_sync.mission_name))
  1755.             {
  1756.                 db_printf(( "Mission not found: %s!\n", other_sync.mission_name));
  1757.                 nm_messagebox(NULL, 1, TXT_OK, TXT_MISSION_NOT_FOUND);
  1758.                 my_sync.sync_id = start_level_num;
  1759.                 serial_sync_abort(0);
  1760.                 return;
  1761.             }
  1762. #endif
  1763.         }
  1764.     }
  1765.     if (com_process_mode != COM_PROCESS_NORMAL)
  1766.         return;
  1767.  
  1768.     memcpy(Players[OtherPlayer].callsign, other_sync.callsign, CALLSIGN_LEN+1);
  1769.     Function_mode = FMODE_GAME;
  1770.     Game_mode &= ~GM_GAME_OVER;
  1771.     Show_kill_list = 1;
  1772.     init_player_stats_game();
  1773.     init_player_stats_level();
  1774. //  Assert(start_level_num > 0);
  1775.     Assert((start_level_num >= Last_secret_level) && (start_level_num <= Last_level));
  1776.     StartNewLevel(start_level_num);
  1777.     printf("Set game mode to %x\n", Game_mode);
  1778. }
  1779.  
  1780. //
  1781. // Modem control functions, dialing, answering, etc.
  1782. //
  1783.  
  1784. void modem_edit_phonebook(newmenu_item *m)
  1785. {
  1786.     int choice, choice2;
  1787.     newmenu_item menu[5];
  1788.     char text[2][100];
  1789.     int default_choice = 0;
  1790.  
  1791.     m[NUM_PHONE_NUM].text = TXT_SAVE;
  1792.  
  1793.     menu[0].text = TXT_NAME; menu[0].type = NM_TYPE_TEXT;
  1794.     menu[1].type = NM_TYPE_INPUT; menu[1].text = text[0]; menu[1].text_len = LEN_PHONE_NAME;
  1795.     menu[2].text = TXT_PHONE_NUM; menu[2].type = NM_TYPE_TEXT;
  1796.     menu[3].type = NM_TYPE_INPUT; menu[3].text = text[1]; menu[3].text_len = LEN_PHONE_NUM;
  1797.     menu[4].text = TXT_ACCEPT; menu[4].type = NM_TYPE_MENU;
  1798.  
  1799. menu:
  1800.     choice = newmenu_do1(NULL, TXT_SEL_NUMBER_EDIT, NUM_PHONE_NUM+1, m, NULL, default_choice);
  1801.     if (choice == -1)
  1802.     {
  1803.         com_load_settings();
  1804.         return;
  1805.     }
  1806.     if (choice == NUM_PHONE_NUM)
  1807.     {
  1808.         // Finished
  1809.         com_save_settings();
  1810.         return;
  1811.     }
  1812.     
  1813.     default_choice = 1;
  1814. edit:
  1815.     // Edit an entry
  1816.     strcpy(menu[1].text, phone_name[choice]);
  1817.     strcpy(menu[3].text, phone_num[choice]);
  1818.  
  1819.     choice2 = newmenu_do1(NULL, TXT_EDIT_PHONE_ENTRY, 5, menu, NULL, default_choice);
  1820.     if (choice2 != -1)
  1821.     {   
  1822.         strcpy(phone_name[choice], menu[1].text);
  1823.         strcpy(phone_num[choice], menu[3].text);
  1824.         sprintf(m[choice].text, "%d. %s \t", choice+1, phone_name[choice]);
  1825.         add_phone_number(m[choice].text, phone_num[choice] );
  1826.     }
  1827.     if (choice2 != 4)
  1828.     {
  1829.         default_choice += 2; if (default_choice > 4) default_choice = 4;
  1830.         goto edit;
  1831.     }
  1832.  
  1833.     default_choice = NUM_PHONE_NUM;
  1834.     goto menu;
  1835. }
  1836.  
  1837.  
  1838.  
  1839. void add_phone_number( char * src, char * num )
  1840. {
  1841.     char p;
  1842.     int l;
  1843.     l = strlen(num);
  1844.     if ( l<15)  {
  1845.         strcat( src, num );
  1846.         return;
  1847.     }
  1848.     p = num[15];
  1849.     num[15] = 0;
  1850.     strcat( src, num );
  1851.     num[15] = p;
  1852.     strcat( src, "..." );
  1853. }
  1854.  
  1855. int modem_dial_menu(void)
  1856. {
  1857.     newmenu_item m[NUM_PHONE_NUM+2];
  1858.     char menu_text[NUM_PHONE_NUM][80];
  1859.     int choice = 0;
  1860.     int i;
  1861.  
  1862. menu:
  1863.     for (i = 0; i < NUM_PHONE_NUM; i++)
  1864.     {
  1865.         m[i].text = menu_text[i];
  1866.         sprintf(m[i].text, "%d. %s \t", i+1, phone_name[i]);
  1867.         add_phone_number(m[i].text, phone_num[i] );
  1868.         m[i].type = NM_TYPE_MENU;
  1869.     }
  1870.  
  1871.     strcat(m[i-1].text, "\n");
  1872.  
  1873.     m[NUM_PHONE_NUM].type = NM_TYPE_MENU; 
  1874.     m[NUM_PHONE_NUM].text = TXT_MANUAL_ENTRY;
  1875.     m[NUM_PHONE_NUM+1].text = TXT_EDIT_PHONEBOOK;
  1876.     m[NUM_PHONE_NUM+1].type = NM_TYPE_MENU;
  1877.  
  1878.     choice = newmenu_do1(NULL, TXT_SEL_NUMBER_DIAL, NUM_PHONE_NUM+2, m, NULL, 0);
  1879.     if (choice == -1) 
  1880.         return -1; // user abort
  1881.  
  1882.     if (choice == NUM_PHONE_NUM+1)
  1883.     {
  1884.         // Edit phonebook
  1885.         modem_edit_phonebook(m);
  1886.         goto menu;
  1887.     }
  1888.  
  1889.     if (choice == NUM_PHONE_NUM)
  1890.     {
  1891.         // Manual entry
  1892.         newmenu_item m2[1];
  1893.         m2[0].type = NM_TYPE_INPUT; m2[0].text = phone_num[NUM_PHONE_NUM]; m2[0].text_len = LEN_PHONE_NUM;
  1894.         choice = newmenu_do(NULL, TXT_ENTER_NUMBER_DIAL, 1, m2, NULL);
  1895.         if (choice == -1)
  1896.             goto menu;
  1897.         else
  1898.             return NUM_PHONE_NUM;
  1899.     }
  1900.  
  1901.     // A phone number was chosen
  1902.     return(choice);
  1903. }
  1904.  
  1905. void
  1906. com_wait_for_connect(int nitems, newmenu_item *menus, int *key, int citem)
  1907. {
  1908.     int result;
  1909.     char input_buffer[81];
  1910.     int baud;
  1911.     char error_mess[5][15] = 
  1912.         {"NO DIAL TONE",
  1913.          "BUSY",
  1914.          "NO ANSWER",
  1915.          "NO CARRIER",
  1916.          "VOICE"};
  1917.     char text[100];
  1918.     int i;
  1919.  
  1920.     int num_error_messages = 5;
  1921.  
  1922.     menus = menus;
  1923.     nitems = nitems;
  1924.     citem = citem;
  1925.  
  1926.     
  1927.     if (GetCd(com_port))
  1928.     {
  1929.         carrier_on = 1;
  1930.     }
  1931.     else
  1932.     {
  1933.         if (carrier_on)
  1934.         {
  1935.             *key = -3;
  1936.             nm_messagebox(NULL, 1, TXT_OK, TXT_CARRIER_LOST);
  1937.             carrier_on = 0;
  1938.             return;
  1939.         }
  1940.     }
  1941.  
  1942.     result = HMInputLine(com_port, 500, input_buffer, 80);
  1943.     
  1944.     if (result == 0) 
  1945.         return;     // Timed out
  1946.  
  1947.     db_printf(( "Modem string: '%s'\n", input_buffer));
  1948.  
  1949.     for (i = 0; i < num_error_messages; i++)
  1950.     {
  1951.         if (!strncmp(input_buffer, error_mess[i], strlen(error_mess[i])))
  1952.         {
  1953.             sprintf(text, "%s %s", TXT_ERR_MODEM_RETURN, input_buffer);
  1954.             nm_messagebox(NULL, 1, TXT_OK, text);
  1955.             *key = -3;
  1956.             return;
  1957.         }
  1958.     }
  1959.  
  1960.     if (strncmp(input_buffer, TXT_CONNECT, 7))
  1961.     {
  1962.         db_printf(( "Non-connect message found.\n"));
  1963.         return; // some other string.  Not an error, but not a connect
  1964.     }
  1965.  
  1966.     sscanf(input_buffer, "CONNECT %d", &baud);
  1967.  
  1968.     db_printf(( "Connect at %d baud.\n", baud));
  1969.  
  1970.     if (baud < 9600)
  1971.     {
  1972.         nm_messagebox(NULL, 1, TXT_OK, TXT_BAUD_GREATER_9600);
  1973.         *key = -3;
  1974.         return;
  1975.     }
  1976.  
  1977.     com_baud_rate = baud;
  1978.     *key = -2;
  1979.     
  1980.     return;
  1981. }
  1982.  
  1983.  
  1984. void
  1985. com_wait_for_ring(int nitems, newmenu_item *menus, int *key, int citem)
  1986. {
  1987.     int result;
  1988.     char input_buffer[81];
  1989.  
  1990.     menus = menus;
  1991.     nitems = nitems;
  1992.     citem = citem;
  1993.  
  1994.     result = HMInputLine(com_port, 500, input_buffer, 80);
  1995.     
  1996.     if ((result <= 0)   || strncmp(input_buffer, TXT_RING, 4))
  1997.         return;
  1998.     
  1999.     *key = -2;
  2000.  
  2001.     return;
  2002.     
  2003. }
  2004.  
  2005. int modem_verify(void)
  2006. {
  2007.     // Is there a modem on this com port or not?
  2008.  
  2009.     int result;
  2010.  
  2011.     HMWaitForOK( 5000, NULL);
  2012.  
  2013. //=================================================
  2014. // This was changed by John in response to a 
  2015. // Creative voice modem not working, since this
  2016. // code doesn't wait for an OK.
  2017.  
  2018. //OLD   HMSendStringNoWait(com_port, "AT", -2);
  2019. //OLD   result = HMSendString(com_port, "AT");
  2020.  
  2021.     HMSendString(com_port, "AT" );
  2022.     result = HMSendString(com_port, "AT");
  2023. //=================================================
  2024.  
  2025.     if (result != 0)
  2026.         return (0);
  2027.     return(1);
  2028. }
  2029.     
  2030. void modem_dialout(void)
  2031. {
  2032.     newmenu_item m[5];
  2033.     char text[50];
  2034.     int choice;
  2035.     
  2036.     if (!serial_active)
  2037.     {
  2038.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NO_SERIAL_OPT);
  2039.         return;
  2040.     }
  2041.  
  2042.     com_enable(); // Open COM port as configured
  2043.  
  2044.     if (!com_open)
  2045.         return;
  2046.  
  2047. //  UseRtsCts(com_port, ON); // use hardware handshaking
  2048.  
  2049. main:
  2050.     if ((choice = modem_dial_menu()) == -1)
  2051.         return; // user aborted
  2052.  
  2053.     show_boxed_message(TXT_RESET_MODEM);
  2054.  
  2055.     // Verify presence of modem
  2056.     if (!modem_verify())
  2057.     {
  2058.         clear_boxed_message();
  2059.         nm_messagebox(NULL, 1, TXT_OK, TXT_NO_MODEM);
  2060.         com_abort();
  2061.         return;
  2062.     }
  2063.  
  2064.     if (strlen(phone_num[choice]) == 0)
  2065.     {
  2066.         clear_boxed_message();
  2067.         nm_messagebox(NULL, 1, TXT_OK, TXT_NO_PHONENUM);
  2068.         goto main;
  2069.     }
  2070.  
  2071.     clear_boxed_message();
  2072.  
  2073.     sprintf(text, "%s\n%s", TXT_DIALING, phone_num[choice]);
  2074.     show_boxed_message(text);
  2075.  
  2076.     // Proceed with the call
  2077.  
  2078.     HMReset( com_port );
  2079.  
  2080.     HMSendString( com_port, modem_init_string );
  2081.     
  2082.     HMDial( com_port, phone_num[choice] );
  2083.     
  2084.     carrier_on = 0;
  2085.  
  2086.     clear_boxed_message();
  2087.  
  2088.     m[0].type=NM_TYPE_TEXT; m[0].text=TXT_ESC_ABORT;
  2089.  
  2090. //repeat:
  2091.     choice = newmenu_do(NULL, TXT_WAITING_FOR_ANS, 1, m, com_wait_for_connect);
  2092.     if (choice != -2) {
  2093.         HMSendStringNoWait(com_port, "", -2);
  2094.         com_abort();
  2095.         return;
  2096.     }
  2097.  
  2098.     // We are now connected to the other modem
  2099.  
  2100.     N_players = 2;
  2101.  
  2102.     master = 1;   // The person who dialed is the master of the connection
  2103.     change_playernum_to(0);
  2104.  
  2105.     if (!com_connect())
  2106.     {
  2107.         Game_mode |= GM_MODEM;
  2108.         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
  2109.     }
  2110.     else {
  2111.         HMSendStringNoWait(com_port, "", -2);
  2112.         com_abort();
  2113.     }
  2114. }
  2115.                                         
  2116.  
  2117. void modem_answer(void)
  2118. {
  2119.     int choice;
  2120.     newmenu_item m[3];
  2121.  
  2122.     if (!serial_active)
  2123.     {
  2124.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NO_SERIAL_OPT);
  2125.         return;
  2126.     }
  2127.  
  2128.     com_enable(); // Open COM port as configured
  2129.  
  2130.     if (!com_open)
  2131.         return;
  2132.  
  2133. //  UseRtsCts(com_port, ON); // use hardware handshaking
  2134.     
  2135.     show_boxed_message(TXT_RESET_MODEM);
  2136.  
  2137.     // Verify presence of modem
  2138.     if (!modem_verify())
  2139.     {
  2140.         clear_boxed_message();
  2141.         nm_messagebox(NULL, 1, TXT_OK, TXT_NO_MODEM);
  2142.         com_abort();
  2143.         return;
  2144.     }
  2145.  
  2146.     HMReset( com_port );
  2147.     
  2148.     HMSendString( com_port, modem_init_string );
  2149.  
  2150.     HMSendString( com_port, "AT"); // To set the DTE rate for RING notification
  2151.  
  2152.     clear_boxed_message();
  2153.  
  2154.     m[0].type=NM_TYPE_TEXT; m[0].text=TXT_ESC_ABORT;
  2155.  
  2156. repeat:
  2157.     choice = newmenu_do(NULL, TXT_WAITING_FOR_CALL, 1, m, com_wait_for_ring);
  2158.     if (choice == -1) {
  2159.         HMSendStringNoWait(com_port, "", -2);
  2160.         com_abort();
  2161.         return;
  2162.     }
  2163.     if (choice != -2)   
  2164.         goto repeat;
  2165.  
  2166.     // Now answer the phone and wait for carrier
  2167.  
  2168.     HMAnswer(com_port);
  2169.  
  2170.     carrier_on = 0;
  2171.  
  2172.     choice = newmenu_do(NULL, TXT_WAITING_FOR_CARR, 1, m, com_wait_for_connect);
  2173.     if (choice != -2) {
  2174.         HMSendStringNoWait(com_port, "", -2);
  2175.         com_abort();
  2176.         return;
  2177.     }
  2178.  
  2179.     // We are now connected to the other modem
  2180.     
  2181.     N_players = 2;
  2182.  
  2183.     master = 0;
  2184.     change_playernum_to(1);
  2185.  
  2186.     if (!com_connect()) 
  2187.     {
  2188.         Game_mode |= GM_MODEM;
  2189.         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
  2190.     }
  2191.     else {
  2192.         HMSendStringNoWait(com_port, "", -2);
  2193.         com_abort();
  2194.     }
  2195. }
  2196.  
  2197. void serial_link_start(void)
  2198. {
  2199.     if (!serial_active)
  2200.     {
  2201.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NO_SERIAL_OPT);
  2202.         return;
  2203.     }
  2204.  
  2205.     com_enable(); // Open COM port as configured
  2206.  
  2207.     if (!com_open)
  2208.         return;
  2209.  
  2210.     N_players = 2;
  2211.  
  2212.     synccnt = 0;
  2213.  
  2214.     srandom(clock());
  2215.     my_sync.sync_time = random();
  2216.     db_printf(( "My rand set to %d.\n", my_sync.sync_time));
  2217.  
  2218.     if (!com_connect()) 
  2219.     {
  2220.         Game_mode |= GM_SERIAL;
  2221.         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
  2222.     } 
  2223.     else
  2224.     {
  2225.         nm_messagebox(NULL, 1, TXT_OK, "%s\n%s", TXT_ERROR, TXT_FAILED_TO_NEGOT);
  2226.     }
  2227. }
  2228.  
  2229. //
  2230. // Syncronization functions
  2231. //
  2232.  
  2233. void
  2234. serial_sync_abort(int val)
  2235. {
  2236.     // Send "I got Sync but it was no good!" packet
  2237.  
  2238.     sendbuf[0] = (char)MULTI_END_SYNC;
  2239.     sendbuf[1] = Player_num;
  2240.     sendbuf[2] = (char)val; // Indicated failure
  2241. #ifndef SHAREWARE
  2242.     sendbuf[3] = my_sync.sync_id;
  2243.     com_send_data(sendbuf, 4, 1);
  2244. #else
  2245.     com_send_data(sendbuf, 3, 1);
  2246. #endif
  2247. }
  2248.     
  2249. int
  2250. com_level_sync(void)
  2251. {
  2252.     // Send between-level sync stuff
  2253.  
  2254.     db_printf(( "entered com_level_sync()\n"));
  2255.  
  2256.     Function_mode = FMODE_MENU; // Prevent the game loop from running during the menus!
  2257.  
  2258.     // At this point, the new level is loaded but the extra objects or players have not 
  2259.     // been removed
  2260.  
  2261.     my_sync.level_num = Current_level_num;
  2262.     my_sync.seg_checksum = netmisc_calc_checksum(Segments, (Highest_segment_index+1) * sizeof(segment));
  2263.     my_sync.kills[0] = kill_matrix[Player_num][0];
  2264.     my_sync.kills[1] = kill_matrix[Player_num][1];
  2265.     my_sync.proto_version = MULTI_PROTO_VERSION;
  2266. #ifndef SHAREWARE
  2267.     my_sync.killed = Players[Player_num].net_killed_total;
  2268. #endif
  2269.     srandom(clock());
  2270.  
  2271.     if (Game_mode & GM_MULTI_COOP)
  2272.         my_sync.difficulty = Player_num;
  2273.     else
  2274.         my_sync.difficulty = random()%MAX_NUM_NET_PLAYERS; // My starting position
  2275.  
  2276.     if (com_sync(Current_level_num))
  2277.     {
  2278.         com_process_mode = COM_PROCESS_MENU;
  2279.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NEGOTIATION_FAIL );
  2280.         longjmp(LeaveGame, 0);
  2281.     }
  2282.  
  2283.     if (my_sync.level_num != other_sync.level_num)
  2284.     {
  2285.         // Fatal error
  2286.         nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s %d\n%s %d", TXT_FATAL_ERROR_LEVEL, my_sync.level_num, TXT_OTHER_LEVEL, other_sync.level_num);
  2287.         longjmp(LeaveGame, 0);
  2288.     }
  2289.  
  2290.     if (my_sync.seg_checksum != other_sync.seg_checksum)
  2291.     {
  2292.         // Checksum failure
  2293.         db_printf(( "My check %d, other check %d.\n", my_sync.seg_checksum, other_sync.seg_checksum));
  2294.         nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s %d %s %s%s", TXT_YOUR_LEVEL, my_sync.level_num, TXT_LVL_NO_MATCH, other_sync.callsign, TXT_CHECK_VERSION);
  2295.         longjmp(LeaveGame, 0);
  2296.     }
  2297.  
  2298.     if (my_sync.proto_version != other_sync.proto_version)
  2299.     {
  2300.         // Version mismatch
  2301.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_DESCENT_NO_MATCH);
  2302.         longjmp(LeaveGame, 0);
  2303.     }
  2304.  
  2305.     db_printf(( "My pos = %d, other pos = %d.\n", my_sync.difficulty, other_sync.difficulty));
  2306.  
  2307.     if ((other_sync.difficulty == my_sync.difficulty) && !master)
  2308.     {
  2309.         // If we chose the same position and I am the slave, choose another
  2310.         my_sync.difficulty = (my_sync.difficulty+1) % MAX_NUM_NET_PLAYERS;
  2311.     }
  2312.  
  2313.     Objects[Players[OtherPlayer].objnum].pos = Player_init[other_sync.difficulty].pos;
  2314.     Objects[Players[OtherPlayer].objnum].orient = Player_init[other_sync.difficulty].orient;
  2315.     obj_relink(Players[OtherPlayer].objnum,Player_init[other_sync.difficulty].segnum);
  2316.     Objects[Players[OtherPlayer].objnum].type = OBJ_PLAYER;
  2317.  
  2318.     Objects[Players[Player_num].objnum].pos = Player_init[my_sync.difficulty].pos;
  2319.     Objects[Players[Player_num].objnum].orient = Player_init[my_sync.difficulty].orient;
  2320.     obj_relink(Players[Player_num].objnum, Player_init[my_sync.difficulty].segnum);
  2321.     Objects[Players[Player_num].objnum].type = OBJ_PLAYER;
  2322.  
  2323.     SerialLastMessage = GameTime;
  2324.  
  2325.     kill_matrix[OtherPlayer][0] = other_sync.kills[0];
  2326.     kill_matrix[OtherPlayer][1] = other_sync.kills[1];
  2327.     Players[Player_num].net_kills_total = kill_matrix[Player_num][OtherPlayer] - kill_matrix[Player_num][Player_num];
  2328.     Players[OtherPlayer].net_kills_total = kill_matrix[OtherPlayer][Player_num] - kill_matrix[OtherPlayer][OtherPlayer];
  2329. //  Players[Player_num].net_killed_total = kill_matrix[0][Player_num] + kill_matrix[1][Player_num];
  2330. //  Players[OtherPlayer].net_killed_total = kill_matrix[0][OtherPlayer] + kill_matrix[1][OtherPlayer];
  2331.     Players[OtherPlayer].net_killed_total = other_sync.killed;
  2332.     Players[OtherPlayer].connected = Players[Player_num].connected = 1;
  2333.  
  2334.     Assert(N_players == 2);
  2335.     Assert(Player_num != OtherPlayer);
  2336.  
  2337.     gr_palette_fade_out(gr_palette, 32, 0);
  2338.  
  2339.     Function_mode = FMODE_GAME;
  2340.     com_process_mode = COM_PROCESS_NORMAL;
  2341.     multi_sort_kill_list();
  2342.     return(0);
  2343. }
  2344.  
  2345.     
  2346. void
  2347. com_send_end_sync(void)
  2348. {
  2349.     // Send "I got Sync" packet
  2350.  
  2351.     sendbuf[0] = (char)MULTI_END_SYNC;
  2352.     sendbuf[1] = Player_num;
  2353.     sendbuf[2] = 1; // Indicates success
  2354. #ifndef SHAREWARE
  2355.     sendbuf[3] = my_sync.sync_id;
  2356.     com_send_data(sendbuf, 4, 2);
  2357. #else
  2358.     com_send_data(sendbuf, 3, 2);
  2359. #endif
  2360. }
  2361.  
  2362. void
  2363. com_send_begin_sync(void)
  2364. {
  2365.     db_printf(( "Sending my sync.\n"));
  2366.     com_send_data((char *)&my_sync, sizeof(com_sync_pack)-3, 1);
  2367. }
  2368.  
  2369. void
  2370. com_process_end_sync(byte *buf)
  2371. {
  2372.     // Process incoming end-sync packet
  2373.  
  2374.     if (buf[2] != 1) {
  2375.         com_process_mode = COM_PROCESS_MENU;
  2376.         return;
  2377.     }
  2378.  
  2379. #ifndef SHAREWARE
  2380.     if (buf[3] == my_sync.sync_id)
  2381. #endif
  2382.         other_got_sync = 1;
  2383. }
  2384.  
  2385. void
  2386. com_process_sync(char *buf, int len)
  2387. {
  2388.     len = len;
  2389.     switch(buf[0])
  2390.     {
  2391.         case MULTI_END_SYNC:
  2392.         {
  2393.             com_process_end_sync(buf);
  2394.             break;
  2395.         }
  2396.         case MULTI_BEGIN_SYNC:
  2397.         {
  2398.             db_printf(( "Incoming begin_sync message.\n"));
  2399.             if (got_sync)
  2400.                 break;
  2401.  
  2402.             memcpy(&other_sync, buf, sizeof(com_sync_pack)-3);
  2403. #ifndef SHAREWARE
  2404.             if (other_sync.sync_id != my_sync.sync_id) 
  2405.             {
  2406.                 db_printf(( "Other sync invalid id, %d != %d.\n", other_sync.sync_id, my_sync.sync_id));
  2407.             }
  2408.             else
  2409. #endif
  2410.             {           
  2411.                 db_printf(( "got other sync size %d.\n", sizeof(com_sync_pack)-3));
  2412.                 got_sync = 1;
  2413.                 com_send_end_sync();
  2414.             }
  2415.             break;
  2416.         }
  2417.     } // switch
  2418.  
  2419.     if (got_sync && other_got_sync)
  2420.     {
  2421.         // OK to start game
  2422. //      db_printf(( "Starting game.\n"));
  2423.         got_sync = 0;
  2424.         other_got_sync = 0;
  2425.         com_process_mode = COM_PROCESS_NORMAL;
  2426.     }
  2427. }
  2428.     
  2429. void
  2430. com_send_sync(void)
  2431. {
  2432.     // Send sync information, depending on the situation
  2433.  
  2434.     if (!other_got_sync)
  2435.     {
  2436.         com_send_begin_sync();
  2437.     }
  2438.     if (got_sync)
  2439.     {
  2440.         com_send_end_sync();
  2441.     }
  2442. }
  2443.  
  2444.  
  2445. void com_sync_poll(int nitems, newmenu_item *menus, int *key, int citem)
  2446. {
  2447.     static fix t1 = 0;
  2448.  
  2449.  
  2450.     if (t1==0) t1=timer_get_approx_seconds();
  2451.  
  2452.     if (!com_open)
  2453.     {
  2454.         *key = -3;
  2455.         return;
  2456.     }
  2457.  
  2458.     if (timer_get_approx_seconds() > t1+F1_0)
  2459.     {
  2460.         com_send_sync();
  2461.         t1 = timer_get_approx_seconds();
  2462.     }
  2463.  
  2464.     Assert(com_process_mode == COM_PROCESS_SYNC);
  2465.         
  2466.     com_process_input();
  2467.  
  2468.     if (com_process_mode == COM_PROCESS_NORMAL)
  2469.     {
  2470.         *key = -2;
  2471.         com_send_sync();
  2472.         db_printf(( "Sync finished.\n"));
  2473.         return;
  2474.     }
  2475.     if (com_process_mode == COM_PROCESS_MENU)
  2476.     {
  2477.         *key = -3;
  2478.         db_printf(( "Sync denied by other side.\n"));
  2479.         return;
  2480.     }
  2481.     return;
  2482. }
  2483.  
  2484. int
  2485. com_sync(int id)
  2486. {
  2487.     // How to handle the end of the level and start of the next level
  2488.     // returns 0 for success or 1 for failure
  2489.  
  2490.     int choice;
  2491.     newmenu_item m[3];
  2492.     int pcx_error;
  2493.  
  2494.     db_printf(( "Entered com_sync\n"));
  2495.  
  2496.     gr_set_current_canvas(NULL);
  2497.     pcx_error = pcx_read_bitmap(Menu_pcx_name, &grd_curcanv->cv_bitmap,grd_curcanv->cv_bitmap.bm_type,NULL);
  2498.     Assert(pcx_error == PCX_ERROR_NONE);
  2499.  
  2500.     com_process_mode = COM_PROCESS_SYNC;
  2501.     got_sync = other_got_sync = 0;
  2502.  
  2503.     com_flush();
  2504.     com_flush();
  2505.  
  2506. #ifndef SHAREWARE
  2507.     my_sync.sync_id = id;
  2508. #endif
  2509.  
  2510.     m[0].type=NM_TYPE_TEXT; m[0].text=TXT_ESC_ABORT;
  2511.     m[1].type = m[2].type = NM_TYPE_MENU;
  2512.     m[1].text = TXT_YES; 
  2513.     m[2].text = TXT_NO;
  2514.  
  2515. repeat:
  2516.     choice = newmenu_do(NULL, TXT_WAIT_OPPONENT, 1, m, com_sync_poll);
  2517.  
  2518.     if (choice == -1) 
  2519.     {
  2520.         choice = newmenu_do1(NULL, TXT_SURE_ABORT_SYNC, 2, m+1, com_sync_poll, 1);
  2521.         if (choice == -1)
  2522.             choice = 1;
  2523.         if (choice == 0)
  2524.             choice = -1;
  2525.     }
  2526.  
  2527.     if ((choice == -1) || (choice == -3)) {
  2528.         return(-1);
  2529.     }
  2530.     else if (choice != -2)
  2531.         goto repeat;
  2532.  
  2533.     return(0);
  2534. }
  2535.  
  2536. void
  2537. com_endlevel(int *secret)
  2538. {
  2539.     // What do we do between levels?
  2540.  
  2541.     Function_mode = FMODE_MENU;
  2542.  
  2543.     gr_palette_fade_out(gr_palette, 32, 0);
  2544.  
  2545.     my_sync.level_num = multi_goto_secret;
  2546.  
  2547.     if (com_sync(-3))
  2548.     {
  2549.         com_process_mode = COM_PROCESS_MENU;
  2550.         nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NEGOTIATION_FAIL);
  2551.         longjmp(LeaveGame, 0);
  2552.     }
  2553.  
  2554.     com_process_mode = COM_PROCESS_ENDLEVEL;
  2555.  
  2556.     if ((multi_goto_secret == 1) || (other_sync.level_num == 1))
  2557.         *secret = 1;
  2558.     else
  2559.         *secret = 0;
  2560.  
  2561.     multi_goto_secret = 0;
  2562.  
  2563.     return;
  2564. }
  2565.  
  2566.  
  2567.